/****************************** Module Header ******************************\
* Module Name:	CppLoadLibrary.cpp
* Project:		CppLoadLibrary
* Copyright (c) Microsoft Corporation.
* 
* This is an example of dynamically loading a DLL using the APIs LoadLibrary, 
* GetProcAddress and FreeLibrary. In contrast with implicit linking (static 
* loading), dynamic loading does not require the LIB file, and the  
* application loads the module just before we call a function in the DLL. 
* The API functions LoadLibrary and GetProcAddress are used to load the DLL 
* and then retrieve the address of a function in the export table. Because 
* we explicitly invoke these APIs, this kind of loading is also referred to 
* as explicit linking. 
* 
* This source is subject to the Microsoft Public License.
* See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
* All other rights reserved.
* 
* History:
* * 1/21/2009 11:04 PM Jialiang Ge Created
\***************************************************************************/

#pragma region Includes
#include "stdafx.h"

#include <windows.h>
#include <assert.h>
#pragma endregion


// The declarations of the functions exported from the module

typedef void	(* LPFNHELLOWORLD)				(_TCHAR**);
// CALLBACK, aka __stdcall, can only be used for stdcall methods. If it is
// used for __cdecl methods, this error will be thrown in runtime: The value 
// of ESP was not properly saved across a function call. This is usually a 
// result of calling a function declared with one calling convention with a
// function pointer declared with a different calling convention.
typedef void	(CALLBACK* LPFNSTDHELLOWORLD)	(_TCHAR**);
typedef int		(* LPFNADD)						(int, int);
typedef int		(CALLBACK* LPFNSTDADD)			(int, int);


/*!
 * \brief
 * Check whether or not the specified module is loaded in the current process.
 * 
 * \param pszModuleName
 * The module name
 */
void IsModuleLoaded(PCTSTR pszModuleName) 
{
	// Get the module in the process according to the module name.
	HMODULE hmod = GetModuleHandle(pszModuleName);

	_tprintf(_T("Module \"%s\" is %sloaded.\n"), pszModuleName, 
		(hmod == NULL) ? _T("not ") : _T(""));
}

int _tmain(int argc, _TCHAR* argv[])
{
	// The name of the module to be dynamically-loaded.
	TCHAR szModuleName[] = _T("CppDllExport");

	// Check whether or not the module is loaded.
	IsModuleLoaded(szModuleName);

	// Dynamically load the library.
	HINSTANCE hDll = LoadLibrary(_T("CppDllExport"));
	if (hDll != NULL)
	{
		// Check whether or not the module is loaded.
		IsModuleLoaded(szModuleName);


		// Call a method: void HelloWorld(_TCHAR** pRet)
		{
			LPFNHELLOWORLD lpfnHelloWorld = (LPFNHELLOWORLD)GetProcAddress(
				hDll, "HelloWorld");
			assert(lpfnHelloWorld);
			_TCHAR* result;
			lpfnHelloWorld(&result);
			_tprintf(_T("Call HelloWorld => %s\n"), result);
		}

		// Call a method: void __stdcall stdcall_HelloWorld(_TCHAR** pRet)
		{
			LPFNSTDHELLOWORLD lpfnStdHelloWorld = (LPFNSTDHELLOWORLD)
				GetProcAddress(hDll, "stdcall_HelloWorld");
			assert(lpfnStdHelloWorld);
			_TCHAR* result;
			lpfnStdHelloWorld(&result);
			_tprintf(_T("Call stdcall_HelloWorld => %s\n"), result);
		}

		// Call a method: int /*__cdecl*/ Add(int a, int b)
		{
			LPFNADD lpfnAdd = (LPFNADD)GetProcAddress(hDll, "Add");
			assert(lpfnAdd);
			_tprintf(_T("Call Add(1, 2) => %d\n"), lpfnAdd(1, 2));
		}

		// Call a method: int __stdcall stdcall_Add(int a, int b)
		{
			LPFNSTDADD lpfnStdAdd = (LPFNSTDADD)GetProcAddress(
				hDll, "_stdcall_Add@8");
			assert(lpfnStdAdd);
			_tprintf(_T("Call stdcall_Add(1, 2) => %d\n"), lpfnStdAdd(1, 2));
		}


		// Attempt to free the library.
		_tprintf(_T("FreeLibrary => %d\n"), FreeLibrary(hDll));

		// Check whether or not the module is loaded.
		IsModuleLoaded(szModuleName);
	}

	return 0;
}

